/* 
 * File:   ProductionRuleContainer.h
 * Author: cpp
 *
 * Created on May 5, 2010, 3:49 PM
 */

#ifndef _PRODUCTIONRULECONTAINER_H
#define	_PRODUCTIONRULECONTAINER_H
#include<string>
#include<map>
#include<vector>
#include"Derivation.h"

using namespace std;

class ProductionRuleContainer {
public:
    ProductionRuleContainer();
    ProductionRuleContainer(const ProductionRuleContainer& orig);
    virtual ~ProductionRuleContainer();
    void addProduction(string NT, string deriv);
    void removeNT(string NT);
    void removeProduction(string NT, int entryNo);
    vector<Derivation>& getProductions(string& NT);
    void print();
    void buildFile(string filename);
    void buildSpec(string filename);
    int count(string NT);
    void updateDRT(DataReferenceTerminal& d);
    void updateRT(ReferenceTerminal& r);

private:
    //strings are consistently ids of nonterminals
    multimap<string, Derivation> prcontainer;
    vector<Derivation> NTvect;
    string NTid;
    vector<Derivation>& getProductions(string NT, vector<Derivation>& dv);

    //We store all Referencing Terminals seperately.

    map<string, DataReferenceTerminal> DRTlist;
    map<string, ReferenceTerminal> RTlist;


};

ProductionRuleContainer::ProductionRuleContainer() {
}

ProductionRuleContainer::ProductionRuleContainer(const ProductionRuleContainer& orig) {
    prcontainer = orig.prcontainer;
}

ProductionRuleContainer::~ProductionRuleContainer() {
}

void ProductionRuleContainer::addProduction(string NT, string deriv) {
    Derivation d;
    d.addDerivString(deriv);

    prcontainer.insert(pair<string, Derivation > (NT, d));

}

void ProductionRuleContainer::print() {
    cout << ".PRULE" << "\n";
    multimap<string, Derivation>::iterator it;
    for (it = prcontainer.begin(); it != prcontainer.end();
            ++it) {
        Derivation& d = (*it).second;
        cout << (*it).first << "\t::==\t" << d << endl;

    }
    cout << ".END_PRULE" << "\n\n";
}

void ProductionRuleContainer::buildFile(string filename) {
    ofstream myfile(filename.c_str(), ios::app);
    myfile << ".PRULE" << "\n";
    multimap<string, Derivation>::iterator it;
    for (it = prcontainer.begin(); it != prcontainer.end();
            ++it) {
        Derivation& d = (*it).second;
        myfile << (*it).first << "\t::==\t" << d << "\n";
    }
    myfile << ".END_PRULE" << "\n\n";
}

//This procedure builds the specification file for accent

void ProductionRuleContainer::buildSpec(string filename) {
    ofstream specfile(filename.c_str(), ios::app);
    string currentNT;
    multimap<string, Derivation>::iterator it;
    for (it = prcontainer.begin(); it != prcontainer.end();
            ++it) {
        //ProductionRuleContainer<NT (string),Derivation>
        const string& NT = (*it).first;
        //Replace <000> start rule with "root" as accent specifies
        string root = "root";
        NonTerminal tNT;
        tNT.setId(NT);
        Derivation& d = (*it).second;
        if (NT == currentNT) {
            specfile << "| ";
            if (NT == "<000>")
                specfile << "{start();} ";
        } else {
            if (NT != "<000>")
                specfile << "; \n";
            currentNT = NT;
            cout << NT << endl;
            if (NT == "<000>") {
                specfile << root << " :\n";
                specfile << "{start();} ";
            } else
                specfile << tNT.getSID() << " :\n";

        }
        specfile << d.getSpecString() << "\n";

    }
    specfile << ";\n";
    specfile.close();
}

vector<Derivation>& ProductionRuleContainer::getProductions(string& NT) {
    return this->getProductions(NT, NTvect);
}

vector<Derivation>& ProductionRuleContainer::getProductions(string NT, vector<Derivation>& dv) {
    pair<multimap<string, Derivation>::iterator,
            multimap<string, Derivation>::iterator> ppp;
    ppp = prcontainer.equal_range(NT);

    // Loop through range of maps of key "b"
    int i = 1;
    for (multimap<string, Derivation>::iterator it2 = ppp.first;
            it2 != ppp.second;
            ++it2) {
        cout << i << "." << (*it2).second << endl;
        i++;
    }
    return dv;
}

void ProductionRuleContainer::removeProduction(string NT, int entryNo) {
    pair<multimap<string, Derivation>::iterator, multimap<string, Derivation>::iterator> ppp;
    ppp = prcontainer.equal_range(NT);
    int i = 1;

    multimap<string, Derivation>::iterator it2 = ppp.first;
    //Nasty Iterator check for entryNo=1
    if (it2 == ppp.second) {
        prcontainer.erase(it2);
        it2 = ppp.second;
    }

    while (it2 != ppp.second) {
        if (i == entryNo) {

            prcontainer.erase(it2);
            break;
        }
        ++it2;
        i++;
    }
}

int ProductionRuleContainer::count(string NT) {
    return prcontainer.count(NT);
}


#endif





